
#include <pic18.h>
#include "hardware.h"
#include "sys_clock.h"
//#include "cmd.h"
#include "macros.h"
#include "gpio.h"
#include "dbg.h"

#define   PINOUT_SAMPLE_PERIOD		100 //MSEC

unsigned char gpio_inp;

/* ================================= OUTPUTS ================================= */
/* ================================= OUTPUTS ================================= */
/* ================================= OUTPUTS ================================= */
typedef struct 
{
	volatile unsigned char *PORT;
	unsigned pin_num 	: 4;
	unsigned p_bit 	: 4;			  	/* pointer to bit; or bit number */
	unsigned int signal;				/* signal to play */
	unsigned char times_to_play;		/* how many times plays the signal; if 0xFF - play always */
	unsigned char f_sample;	  			/* sample period  */
	unsigned char f_sample_cnt;  	/* frequency divider */
}pinout_t;


pinout_t outputs[] = 
{
	{(volatile unsigned char*)&PORTB, 5, 0,  0x0000, PINOUT_PLAY_ALWAYS, 10, 0}, /* Relay1 */
	{(volatile unsigned char*)&PORTB, 4, 0,  0x0000, PINOUT_PLAY_ALWAYS, 10, 0}, /* Relay2 */
	{(volatile unsigned char*)&PORTB, 3, 0,  0x0010, PINOUT_PLAY_ALWAYS, 2, 0}, /* LED D1 (SH_BASE schematic) */
};

/* ================================= INPUTS ================================= */
/* ================================= INPUTS ================================= */
/* ================================= INPUTS ================================= */

typedef struct 
{
	volatile unsigned char *PORT;
	unsigned pin 	: 4;
	unsigned state	: 4;			 
	unsigned char deb;  	
	unsigned char deb_cnt;  			  /* debounce */
}pininp_t;

pininp_t inputs[] = 
{
	{(volatile unsigned char*)&PORTE,3,1,5,0},
};


#define   GPIO_OUT_COUNT		(SIZEOF_ARRAY(outputs))
#define   GPIO_INP_COUNT		(SIZEOF_ARRAY(inputs))

#define   PORT_DIR_SHIFT		(0x12) 
 
void gpio_init ( void )
{
	unsigned int i;
	volatile unsigned char *p;

	/* set direction as OUTPUT */
	for ( i = 0; i < GPIO_OUT_COUNT; i++ )
	{
		p = outputs[i].PORT + PORT_DIR_SHIFT;
 
		*p &= ~((unsigned long)1<<outputs[i].pin_num);
	}
	
	/* set direction as inputs */
	for ( i = 0; i < GPIO_INP_COUNT; i++ )
	{
		p = inputs[i].PORT + PORT_DIR_SHIFT;
		*p |= ((unsigned long)1<<inputs[i].pin);
	}
}

void pout_set ( unsigned char out_num, unsigned int signal, unsigned short f_sample /* ms see PINOUT_SAMPLE_PERIOD*/, 
						unsigned char times_to_play )
{
	if ( out_num >= GPIO_OUT_COUNT )
	{
		return ;
	}

	outputs[out_num].signal = signal;
	outputs[out_num].times_to_play = times_to_play;
	outputs[out_num].p_bit = 0;
	outputs[out_num].f_sample = (f_sample / PINOUT_SAMPLE_PERIOD); 
	outputs[out_num].f_sample_cnt = 0;
	
	if ( outputs[out_num].signal & ((unsigned int)1<<outputs[out_num].p_bit) )
	{
		*(outputs[out_num].PORT) |= ((unsigned long)1<<outputs[out_num].pin_num);
	}
	else
	{
		*(outputs[out_num].PORT) &= ~((unsigned long)1<<outputs[out_num].pin_num);
	}
} 

void pout_pulse ( unsigned char out_num, unsigned char active_level, unsigned int pulse_time_ms ) 
{	
	unsigned int signal = 0xfffe;
	if ( active_level )
		signal = 1;
	pout_set(out_num,signal,pulse_time_ms,1);
}

void pout_out ( unsigned char out_num, unsigned char out_state )
{
	unsigned int state = 0;
	if ( out_state )
		state = 0xffff;

	pout_set(out_num,state,1,1);
}


signed char pout_read ( unsigned char out_num )
{
	if ( out_num >= GPIO_OUT_COUNT )
		return -1;

	return READ_BIT(*(outputs[out_num].PORT), outputs[out_num].pin_num);
}

#define   OUT_PIN_SET()			*(outputs[i].PORT) |=  ((unsigned char)1<<outputs[i].pin_num)
#define   OUT_PIN_RESET()		*(outputs[i].PORT) &= ~((unsigned char)1<<outputs[i].pin_num)

void gpio_drv ( void )
{
	unsigned char i;

	if ( !SYS_CLOCK(PINOUT_SAMPLE_PERIOD) )
		return;

#if 0
	/* Inputs */
	for ( i = 0; i < GPIO_INP_COUNT; i++ )
	{
		if ( inputs[i].state )
		{
			if ( !READ_BIT(*(inputs[i].PORT), inputs[i].pin)  )
			{
				if ( ++inputs[i].deb_cnt > inputs[i].deb )
				{
					inputs[i].deb_cnt = 0;
					inputs[i].state = 0;
					gpio_inp = i;
					//dbg(" ___inp: %x", gpio_inp); //Dima
					//dbg(" ___inp: "); //Dima
				}
			}
			else
			{
				inputs[i].deb_cnt = 0;
			}
		}
		else
		{
			if ( READ_BIT(*(inputs[i].PORT), inputs[i].pin)  )
			{
				if ( ++inputs[i].deb_cnt > inputs[i].deb )
				{
					inputs[i].deb_cnt = 0;
					inputs[i].state = 1;
					gpio_inp = i + 0x80;
						dbg(" ^^^inp: %x", gpio_inp); //Dima
				}
			}
			else
			{
				inputs[i].deb_cnt = 0;
			}
		}
	}
#endif
	

	/* Outputs */
	for ( i = 0; i < GPIO_OUT_COUNT; i++ )
	{
		if ( outputs[i].signal & ((unsigned int)1<<outputs[i].p_bit) )
		{
			OUT_PIN_SET();
		}
		else
		{
			OUT_PIN_RESET();
		}

		if ( outputs[i].times_to_play && ++outputs[i].f_sample_cnt >= outputs[i].f_sample )
		{
			outputs[i].f_sample_cnt = 0;
				
			if ( outputs[i].p_bit == 15 && outputs[i].times_to_play < PINOUT_PLAY_ALWAYS )
				outputs[i].times_to_play--;

			if ( outputs[i].times_to_play )
			{
				outputs[i].p_bit++;
				//outputs[i].p_bit %= 16;
			}
		}
	} 

}
